package se.webbzon.boltzmann.menu;

import java.awt.image.ImageObserver;

import se.webbzon.boltzmann.configuration.Controls;
import se.webbzon.boltzmann.debug.Debug;
import se.webbzon.boltzmann.game.Game;
import se.webbzon.boltzmann.game.GameManager;
import se.webbzon.boltzmann.game.environment.GameEnvironment;
import se.webbzon.boltzmann.player.Player;
import se.webbzon.boltzmann.world.GameWorldLoader;
import se.webbzon.oschi01.worldarea.WorldArea;

public class GamePage extends MFlowPage {
	
	// The number of rows and columns of a game menu page
	private static final int rows = 2, columns = 3;
	
	// The layout of this game menu page
	private final AbstractGameMenuLayout layout;
	
	// The game manager associated with this menu page
	private final GameManager manager;
	
	// The game radio group
	private final MRadioGroup gameGroup;
	
	// The persistent items of this page
	private final MItem refresh, delete, next, previous;
	
	// The overlays of this page
	private final MOverlay refreshOverlay;
	private final ErrorOverlay errorOverlay;
	
	// The current page and the number of pages
	private int page, pages;
	
	/*============================================================
	Constructors
	============================================================*/

	public GamePage(ImageObserver observer, AbstractGameMenuLayout layout, 
					MPage parent, GameManager manager, String name) {
		super(observer, layout.getPageLayout(), parent,name);
		this.layout = layout;
		this.manager = manager;
		gameGroup = new GameRadioGroup();
		refresh = new RefreshButton();
		delete = new DeleteButton();
		next = new NextButton();
		previous = new PreviousButton();
		refreshOverlay = new MOverlay(layout.getButtonLayout(),"Refreshing...");
		refreshOverlay.setVisible(false);
		errorOverlay = new ErrorOverlay(layout.getButtonLayout(),"");
		errorOverlay.setVisible(false);
	}
	
	/*============================================================
	Public Methods
	============================================================*/

	@Override public void onEnter(GameMenu menu) {
		Controls.instance().getInput().addListener(errorOverlay);
	}

	@Override public void onLeave(GameMenu menu) {
		Controls.instance().getInput().removeListener(errorOverlay);
	}
	
	/** Refreshes and rebuild the page. **/
	public void refreshAndRebuildAll() {
		addItem(refreshOverlay);
		addItem(errorOverlay);
		refresh();
		rebuildAll();
	}
	
	/*============================================================
	Private Methods
	============================================================*/
	
	/** Rebuilds the page. **/
	private final void rebuildAll() {
		removeAll();
		addItem(refreshOverlay);
		addItem(errorOverlay);
		rebuildTop();
		rebuildMiddle();
		rebuildBottom();
	}
	
	/** Rebuilds the top items of the game page. **/
	private final void rebuildTop() {
		addItem(new PageLabel(getImageObserver(), layout.getLabelLayout(), this));
		addRow(0.25);
		addItem(new ReturnButton(getImageObserver(), layout.getButtonLayout(), getParent()));
		addRow();
		
		addItem(refresh);
		addRow(0.25);
		addItem(new StartButton());
		addItem(new NewButton());
		addItem(delete);
		addRow();
	}
	
	/** Rebuilds the middle items of the game page. **/
	private final void rebuildMiddle() {
		final int games = manager.games();
		final int gamesPerPage = rows * columns;
		for (int row = 0; row < rows; row++) {
			for (int col = 0; col < columns; col++) {
				int index = gamesPerPage * page + row + rows * col;
				if (index < games) {
					Game game = manager.getGame(index);
					addItem(new GameRadio(getImageObserver(),layout.getButtonLayout(),index,game));
				}
			}
			addRow(0.25);
		}
	}
	
	/** Rebuilds the bottom items of the game page. **/
	private final void rebuildBottom() {
		if (manager.games() > rows * columns) {
			addItem(previous);
			addItem(new GamePageLabel());
			addItem(next);
		}
	}
	
	/** Refreshes the game list data. **/
	private final void refresh() {
		refreshOverlay.setVisible(true);
		try {
			manager.refresh();
			final int games = manager.games();
			page = 0;
			pages = 1 + games / 6;
			
			if (manager.games() > 0)
				gameGroup.setValue(manager.getGame(0));
			else
				gameGroup.setValue(null);
		} catch (Exception e) {
			Debug.report(e);
			errorOverlay.setText(e.getMessage());
			errorOverlay.setVisible(true);
		}
		refreshOverlay.setVisible(false);
	}
	
	/*============================================================
	Private Classes
	============================================================*/

	/** The game radio group. **/
	private final class GameRadioGroup extends MRadioGroup {

		@Override public void onChangeValue(Object value) {};
		
	}
	
	/** The game radio button. **/
	private final class GameRadio extends MRadio {

		public GameRadio(ImageObserver observer, ButtonLayout layout, int index, Game game) {
			super(observer, layout, gameGroup, index, false, game.getName());
		}
		
	}
	
	/** The "refresh" button. **/
	private final class RefreshButton extends MButton {

		public RefreshButton() {
			super(getImageObserver(), layout.getButtonLayout(), false, "Refresh");
		}

		@Override public void onClick(GameMenu menu) {
			refresh();
			rebuildAll();
			menu.setSelection(this);
		}
		
	}
	
	/** The "new game" button. **/
	private final class NewButton extends MButton {

		public NewButton() {
			super(getImageObserver(), layout.getButtonLayout(), false, "New Game");
		}

		@Override public void onClick(GameMenu menu) {
			try {
				manager.createGame("New game");
				rebuildAll();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
	}
	
	/** The "delete game" button. **/
	private final class DeleteButton extends MButton {

		public DeleteButton() {
			super(getImageObserver(), layout.getButtonLayout(), false, "Delete Game");
		}

		@Override public void onClick(GameMenu menu) {
			Object index = gameGroup.getValue();
			if (index != null) try {
				if (!manager.removeGame((int) index)) {
					System.out.println("Could not remove game!");
				} else {
					gameGroup.setValue(null);
					menu.setSelection(this);
					rebuildAll();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
	}
	
	/** The "start" button. **/
	private final class StartButton extends MButton {

		public StartButton() {
			super(getImageObserver(), layout.getButtonLayout(), false, "Start");
		}

		@Override public void onClick(GameMenu menu) {
			Object index = gameGroup.getValue();
			if (index != null) {
				Game game = manager.getGame((int) index);
				// Load the game
				try {
					GameEnvironment genv = game.load(menu.getGameConfiguration());
					WorldArea currentWorld = menu.getWorld();
					Player player = genv.getPlayers().iterator().next();
					String worldAreaName = player.getLocation().getWorldAreaName();
					byte portalId = player.getLocation().getPortalId();
					GameWorldLoader loader = new GameWorldLoader(genv,worldAreaName,player,portalId);
					WorldArea gameWorld = loader.load();
					currentWorld.destroyAll();
					currentWorld.gotoWorldArea(gameWorld);
				} catch (Exception e) {
					Debug.report(e);
				}
				
			}
		}
		
	}
	
	/** The "next" button. **/
	private final class NextButton extends MButton {

		public NextButton() {
			super(getImageObserver(), layout.getButtonLayout(), false, "Next >>");
		}

		@Override public void onClick(GameMenu menu) {
			if (page < pages - 1) {
				page++;
				rebuildAll();
				menu.setSelection(this);
			}
		}
		
	}
	
	/** The "previous" button. **/
	private final class PreviousButton extends MButton {

		public PreviousButton() {
			super(getImageObserver(), layout.getButtonLayout(), false, "<< Previous");
		}

		@Override public void onClick(GameMenu menu) {
			if (page > 0) {
				page--;
				rebuildAll();
				menu.setSelection(this);
			}
		}
		
	}
	
	/** The game page label. **/
	private final class GamePageLabel extends MLabel {

		public GamePageLabel() {
			super(getImageObserver(), layout.getLabelLayout(), false, (page + 1) + "/" + pages);
		}
		
	}
	
}
